﻿//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Ext.h".
//-------------------------------------------------------------------

#include "GLStateManager.h"

namespace UX_STL
{
namespace GLShell
{

	static const TSMGLState	a_states[]	= {	TSMGLState( GL_COLOR_LOGIC_OP,				false ),	// OGL 1.1
											TSMGLState( GL_CULL_FACE,					false ),
											TSMGLState( GL_DEPTH_CLAMP,					false ),	// OGL 3.2
											TSMGLState( GL_DEPTH_TEST,					false ),
											TSMGLState( GL_DITHER,						false ),
											TSMGLState( GL_LINE_SMOOTH,					false ),
											TSMGLState( GL_MULTISAMPLE,					false ),	// OGL 1.3
											TSMGLState( GL_POLYGON_OFFSET_FILL,			false ),	// OGL 1.1
											TSMGLState( GL_POLYGON_OFFSET_LINE,			false ),	// OGL 1.1
											TSMGLState( GL_POLYGON_OFFSET_POINT,		false ),	// OGL 1.1
											TSMGLState( GL_POLYGON_SMOOTH,				false ),
											TSMGLState( GL_PRIMITIVE_RESTART,			false ),	// OGL 3.1
											TSMGLState( GL_SAMPLE_ALPHA_TO_COVERAGE,	false ),	// OGL 1.3
											TSMGLState( GL_SAMPLE_ALPHA_TO_ONE,			false ),	// OGL 1.3
											TSMGLState( GL_SAMPLE_COVERAGE,				false ),	// OGL 1.3
											TSMGLState( GL_SCISSOR_TEST,				false ),
											TSMGLState( GL_STENCIL_TEST,				false ),
											TSMGLState( GL_TEXTURE_CUBE_MAP_SEAMLESS,	false ),	// OGL 3.2
											TSMGLState( GL_PROGRAM_POINT_SIZE,			false ),
											TSMGLState( GL_RASTERIZER_DISCARD,			false ),
											TSMGLState( GL_FRAMEBUFFER_SRGB,			false )	};	// OGL 3.3


/*
=================================================
	конструктор
=================================================
*/
	GLStateManager::GLStateManager():
		/*Texture*/			_uCurLayer(0),							_aTexLayers(),
		/*Program*/			_uProgram(0),							_uProgramPipeline(0),
		/*Cull Face*/		_eCullMode(gl_face::_INIT),
		/*Polygon Mode*/	_ePolygonMode(gl_polygon_mode::FILL),	_eFrontFace(gl_front_face::CCW),
		/*Buffers*/			_uVAO(0),								_uReadFBO(0),
							_uDrawFBO(0),							_uRBO(0),
							_uIBO(0),								
		/*Tess*/			_uPatchSize(0),							_bTessEnable(false),
		/*Locks*/			_bLockTexture(false),					_bLockSampler(false),
							_bLockProgram(false),					_bLockVAO(false),
							_bLockFBO(false)
	{
	}

/*
=================================================
	деструктор
=================================================
*/
	GLStateManager::~GLStateManager()
	{
		_aStates.Clear();
		_aTexLayers.Clear();
	}
	
/*
=================================================
	инициализация
=================================================
*/
	bool GLStateManager::_Init()
	{
		_aTexLayers.Resize( C_GL_MAX_TEXTURE_IMAGE_UNITS );
		_aStates.Copy( uni_array< const TSMGLState >( a_states ) );

		_sTexStack.SetDefault( GLTexLayer() );
		_sDrawFBOStack.SetDefault( 0 );
		_sReadFBOStack.SetDefault( 0 );
		_sVAOStack.SetDefault( 0 );
		return true;
	}

/*
=================================================
	сбросить состояния
=================================================
*/
	void GLStateManager::Refresh()
	{
		for (usize i = 0; i < _aTexLayers.Count()-1; ++i)
		{
			glBindMultiTexture( GL_TEXTURE0 + (GLenum) i, GL_TEXTURE_2D, 0 );
			glBindSampler( (GLuint) i, 0 );

			_aTexLayers[i].eTarget	= gl_texture::TEXTURE_2D;
			_aTexLayers[i].uID		= 0;
			_aTexLayers[i].uSampler	= 0;
		}

		FOR( i, _aStates )
			_aStates[i].bEnabled = glIsEnabled( _aStates[i].uGLEnum ) == GL_TRUE;

		_sTexStack.Clear();
		_sVAOStack.Clear();
		_sDrawFBOStack.Clear();
		_sReadFBOStack.Clear();

		_sViewportStack.Clear();
		_sViewportStack.Get().sScissorStack.Clear();
		_sViewportStack.Get().sScissorStack.Set( _sViewportStack.Get().sArea );

		glActiveTexture( GL_TEXTURE0 );

		glUseProgram( 0 );
		glBindProgramPipeline( 0 );

		glBindVertexArray( 0 );
		glBindFramebuffer( GL_FRAMEBUFFER, 0 );
		glBindBuffer( gl_buffer::INDEX,  0 );
		glBindBuffer( gl_buffer::VERTEX, 0 );

		glBlendEquation( GL_FUNC_ADD );
		glBlendFunc( GL_ONE, GL_ZERO );
		glLogicOp( GL_COPY );
		glDepthFunc( GL_LEQUAL );
		glDepthMask( GL_TRUE );
		glDisable( GL_BLEND );

		glStencilFunc( GL_ALWAYS, 0, 1 );
		glStencilMask( 1 );

		glCullFace( GL_BACK );
		glFrontFace( GL_CCW );
		glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
		glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
		
		_uCurLayer			= 0;

		_uProgram			= 0;
		_uProgramPipeline	= 0;
		
		_uIBO				= 0;
		_uVAO				= 0;
		_uReadFBO			= 0;
		_uDrawFBO			= 0;
		_uRBO				= 0;

		_eDepthFunc			= gl_compare::LEQUAL;
		_bDepthMask			= true;

		_sStencil			= TStencilState();

		FOR( i, _aColorBuffers ) {
			_aColorBuffers[i]			= TColorBuffer();
			_aColorBuffers[i].uIndex	= (uint8) i;
		}

		_eCullMode			= gl_face::BACK;
		_ePolygonMode		= gl_polygon_mode::FILL;
		_eFrontFace			= gl_front_face::CCW;

		_bLockTexture		= false;
		_bLockSampler		= false;
		_bLockProgram		= false;
		_bLockVAO			= false;
		_bLockFBO			= false;

		OPENGL_CHECK_ERRORS();
	}
	
/*
=================================================
	отключает все текстуры
=================================================
*/
	void GLStateManager::UnbindTextures()
	{
		for (usize i = 0; i < _aTexLayers.Count()-1; ++i)
		{
			GL_CALL( glBindMultiTexture( GL_TEXTURE0 + (GLenum) i, GL_TEXTURE_2D, 0 ) );
			_aTexLayers[i].eTarget	= gl_texture::_UNKNOWN;
			_aTexLayers[i].uID		= 0;
			_uCurLayer				= (uint) i;
		}
	}
	
/*
=================================================
	отключает все сэмплеры
=================================================
*/
	void GLStateManager::UnbindSamplers()
	{
		FOR( i, _aTexLayers )
		{
			GL_CALL( glBindSampler( (GLuint) i, 0 ) );
			_aTexLayers[i].uSampler	= 0;
		}
	}

//-------------------------------------------------------------------
	
}	// GLShell
}	// UX_STL
